package com.bestcem.xm.componet.sms.aliyun.core;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.HttpClientConfig;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.utils.StringUtils;
import com.bestcem.xm.componet.sms.aliyun.AliyunSmsProperties;
import com.bestcem.xm.componet.sms.aliyun.kit.Utils;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Slf4j
public class AliyunSmsClient {

    /**
     * key 是阿里云 的templateCode
     */
    private final Map<String, IAcsClient> acsClients = new HashMap<>();

    private Map<String, AliyunSmsTemplate> smsTemplates;


    public AliyunSmsClient(AliyunSmsProperties aliyunSmsProperties) {
        if (aliyunSmsProperties == null || aliyunSmsProperties.getSmsTemplates() == null) {
            log.warn("阿里云短信通道未配置,短信发送暂不可用");
            return;
        }

        this.smsTemplates = aliyunSmsProperties.getSmsTemplates();

        String globalSignName = aliyunSmsProperties.getBaseSetting().getSignName();
        String accessKeyId = aliyunSmsProperties.getBaseSetting().getAccessKeyId();
        String accessKeySecret = aliyunSmsProperties.getBaseSetting().getAccessKeySecret();
        String proxyIp = aliyunSmsProperties.getBaseSetting().getProxyIp();
        Integer proxyPort = aliyunSmsProperties.getBaseSetting().getProxyPort();

        smsTemplates.forEach((k, v) -> {
            final IClientProfile clientProfile = DefaultProfile.getProfile("default", accessKeyId, accessKeySecret);
            if (StringUtils.isEmpty(v.getSignName())) {
                v.setSignName(globalSignName);
            }
            // 设置代理参数
            if (!StringUtils.isEmpty(proxyIp)) {
                HttpClientConfig clientConfig = HttpClientConfig.getDefault();
                clientConfig.setHttpProxy(String.format("http://%s:%s", proxyIp, proxyPort));
                clientConfig.setHttpsProxy(String.format("http://%s:%s", proxyIp, proxyPort));
                clientProfile.setHttpClientConfig(clientConfig);
            }

            IAcsClient acsClient = new DefaultAcsClient(clientProfile);
            this.acsClients.put(k, acsClient);
        });

    }

    /**
     * 发送短信验证码. (使用第一个模板)
     *
     * @param phoneNumbers 手机号码(中国)
     * @param code         验证码
     * @return 6 位数的随机码
     */
    public String sendVerificationCode(final String code, final String... phoneNumbers) {
        checkSmsTemplate();
        Utils.checkPhoneNumber(phoneNumbers);
        int size = smsTemplates.size();
        if (size == 0) {
            throw new IllegalArgumentException("Invalid Templates");
        }

        String smsTemplateKey = smsTemplates.keySet().iterator().next();
        final AliyunSmsTemplate aliyunSmsTemplate = this.smsTemplates.get(smsTemplateKey);
        Objects.requireNonNull(aliyunSmsTemplate, () -> "AliyunSmsTemplate must be not null, key:" + smsTemplateKey);

        aliyunSmsTemplate.setTemplateCode(smsTemplateKey);
        aliyunSmsTemplate.setTemplateParam(Collections.singletonMap("code", code));
        aliyunSmsTemplate.setPhoneNumbers(Arrays.asList(phoneNumbers));
        send(aliyunSmsTemplate);
        return code;
    }

    /**
     * 校验是否可用
     */
    private boolean checkSmsTemplate() {
        if (smsTemplates == null || this.smsTemplates.isEmpty()) {
            log.warn("阿里云短信通道配置错误,短信发送暂不可用,验证码注意 日志输出");
            return false;
        } else {
            return true;
        }
    }

    /**
     * 发送短信验证码.(通过短信模板key)
     *
     * @param smsTemplateKey 模板key
     * @param phoneNumbers   手机号码(中国)
     * @param code           验证码
     * @return 验证码
     */
    public String sendCodeByKey(final String smsTemplateKey, final String code, final String... phoneNumbers) {
        if (!checkSmsTemplate()) {
            return null;
        }
        Utils.checkPhoneNumber(phoneNumbers);
        final AliyunSmsTemplate aliyunSmsTemplate = this.smsTemplates.get(smsTemplateKey);
        Objects.requireNonNull(aliyunSmsTemplate, () -> "AliyunSmsTemplate must be not null, key:" + smsTemplateKey);

        aliyunSmsTemplate.setTemplateCode(smsTemplateKey);
        aliyunSmsTemplate.setTemplateParam(Collections.singletonMap("code", code));
        aliyunSmsTemplate.setPhoneNumbers(Arrays.asList(phoneNumbers));
        send(aliyunSmsTemplate);
        return code;
    }

    /**
     * 发送短信验证码.(默认第一个渠道)
     *
     * @param phoneNumbers 手机号码(中国)
     * @param code         验证码
     * @return 验证码
     */
    public String sendCode(final String code, final String... phoneNumbers) {
        if (!checkSmsTemplate()) {
            return null;
        }

        String defaultKey = smsTemplates.keySet().iterator().next();
        Utils.checkPhoneNumber(phoneNumbers);
        final AliyunSmsTemplate aliyunSmsTemplate = this.smsTemplates.get(defaultKey);
        Objects.requireNonNull(aliyunSmsTemplate, () -> "AliyunSmsTemplate must be not null, key:" + defaultKey);

        aliyunSmsTemplate.setTemplateCode(defaultKey);
        aliyunSmsTemplate.setTemplateParam(Collections.singletonMap("code", code));
        aliyunSmsTemplate.setPhoneNumbers(Arrays.asList(phoneNumbers));
        send(aliyunSmsTemplate);
        return code;
    }

    /**
     * 发送短信验证码.(通过短信模板key)
     *
     * @param smsTemplateKey 模板key
     * @param phoneNumbers   手机号码(中国)
     * @param params         模板参数
     */
    public void sendParamByKey(final String smsTemplateKey, final Map<String, String> params,
                               final String... phoneNumbers) {
        if (!checkSmsTemplate()) {
            return;
        }
        Utils.checkPhoneNumber(phoneNumbers);
        final AliyunSmsTemplate aliyunSmsTemplate = this.smsTemplates.get(smsTemplateKey);
        Objects.requireNonNull(aliyunSmsTemplate, () -> "AliyunSmsTemplate must be not null, key:" + smsTemplateKey);

        aliyunSmsTemplate.setTemplateCode(smsTemplateKey);
        aliyunSmsTemplate.setTemplateParam(params);
        aliyunSmsTemplate.setPhoneNumbers(Arrays.asList(phoneNumbers));
        send(aliyunSmsTemplate);
    }

    /**
     * 发送短信.
     *
     * @param smsTemplateKey 预置短信模板 key
     */
    public void send(final String smsTemplateKey) {
        if (!checkSmsTemplate()) {
            return;
        }
        final AliyunSmsTemplate aliyunSmsTemplate = this.smsTemplates.get(smsTemplateKey);
        aliyunSmsTemplate.setTemplateCode(smsTemplateKey);
        Objects.requireNonNull(aliyunSmsTemplate, () -> "AliyunSmsTemplate must be not null, key:" + smsTemplateKey);

        send(aliyunSmsTemplate);
    }

    /**
     * 发送短信.
     *
     * @param smsTemplateKey 预置短信模板 key
     * @param phoneNumbers   手机号码，优先于预置短信模板中配置的手机号码
     */
    public void send(final String smsTemplateKey, final String... phoneNumbers) {
        if (!checkSmsTemplate()) {
            return;
        }
        final AliyunSmsTemplate aliyunSmsTemplate = this.smsTemplates.get(smsTemplateKey);
        aliyunSmsTemplate.setTemplateCode(smsTemplateKey);
        Objects.requireNonNull(aliyunSmsTemplate, () -> "AliyunSmsTemplate must be not null, key:" + smsTemplateKey);

        aliyunSmsTemplate.setPhoneNumbers(Arrays.asList(phoneNumbers));
        send(aliyunSmsTemplate);
    }

    /**
     * 发送短信.
     *
     * @param aliyunSmsTemplate 短信模板
     */
    public void send(final AliyunSmsTemplate aliyunSmsTemplate) {
        Objects.requireNonNull(aliyunSmsTemplate);
        if (!checkSmsTemplate()) {
            return;
        }

        final CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("dysmsapi.aliyuncs.com");
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendSms");
        request.putQueryParameter("PhoneNumbers", String.join(",", aliyunSmsTemplate.getPhoneNumbers()));
        request.putQueryParameter("SignName", aliyunSmsTemplate.getSignName());
        request.putQueryParameter("TemplateCode", aliyunSmsTemplate.getTemplateCode());
        request.putQueryParameter("TemplateParam", Utils.toJsonStr(aliyunSmsTemplate.getTemplateParam()));
        try {
            IAcsClient iAcsClient = acsClients.get(aliyunSmsTemplate.getTemplateCode());
            final CommonResponse response = iAcsClient.getCommonResponse(request);
            Utils.checkSmsResponse(response);
        } catch (final ClientException e) {
            throw new AliyunSmsException(e);
        }
    }

}
